package io.renren.controller;

import io.renren.annotation.Login;
import io.renren.annotation.LoginUser;
import io.renren.cloud.OSSFactory;
import io.renren.common.exception.RRException;
import io.renren.common.utils.ConfigConstant;
import io.renren.common.utils.DateUtils;
import io.renren.common.utils.DecimalUtils;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.ProjectConstant;
import io.renren.common.utils.R;
import io.renren.common.utils.SMSManages;
import io.renren.common.validator.Assert;
import io.renren.common.validator.ValidatorUtils;
import io.renren.entity.CtocOrderEntity;
import io.renren.entity.CtocTransCountEntity;
import io.renren.entity.CtocTransactionEntity;
import io.renren.entity.MemberEntity;
import io.renren.entity.SysOssEntity;
import io.renren.form.BuyForm;
import io.renren.form.MemberOtherForm;
import io.renren.form.SellForm;
import io.renren.service.CtocOrderService;
import io.renren.service.CtocTransCountService;
import io.renren.service.CtocTransactionService;
import io.renren.service.MemberService;
import io.renren.service.SysConfigService;
import io.renren.service.SysOssService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import java.io.ByteArrayOutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import net.coobird.thumbnailator.Thumbnails;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import springfox.documentation.annotations.ApiIgnore;

import com.baomidou.mybatisplus.mapper.EntityWrapper;

/**
 * 订单接口
 *
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2017-03-23 15:31
 */
@RestController
@RequestMapping("/api/order")
@Api(tags = "订单接口")
public class ApiOrderController extends AbstractController {

	@Autowired
	MemberService memberService;

	@Autowired
	CtocOrderService ctocOrderService;

	@Autowired
	CtocTransactionService ctocTransactionService;

	@Autowired
	CtocTransCountService ctocTransCountService;

	@Autowired
	SysConfigService sysConfigService;

	@Autowired
	SysOssService sysOssService;

	@Login
	@PostMapping("orderCount")
	@ApiOperation("订单统计")
	public R orderCount(@ApiIgnore @RequestAttribute("userId") long userId) {
		Integer needPay = ctocTransactionService.selectCount(new EntityWrapper<CtocTransactionEntity>().eq("buyer_member_id", userId).eq("status",
				ProjectConstant.CTOC_TRANS_STATUS_NEEDPAY));
		Integer paid = ctocTransactionService.selectCount(new EntityWrapper<CtocTransactionEntity>().eq("seller_member_id", userId).eq("status",
				ProjectConstant.CTOC_TRANS_STATUS_PAID));
		Integer finish = ctocTransactionService.selectCount(new EntityWrapper<CtocTransactionEntity>().eq("status", ProjectConstant.CTOC_TRANS_STATUS_CONFIRMED).andNew()
				.eq("buyer_member_id", userId).or().eq("seller_member_id", userId));
		return R.ok().put("needPay", needPay).put("paid", paid).put("finish", finish);
	}

	@Login
	@PostMapping("list")
	@ApiOperation("挂单列表")
	@SuppressWarnings("unchecked")
	public R list(@ApiIgnore @RequestParam Map<String, Object> params) {
		params.put("status", ProjectConstant.CTOC_ORDER_STATUS_SUBMIT);
		PageUtils page = ctocOrderService.queryPage(params);
		List<CtocOrderEntity> list = (List<CtocOrderEntity>) page.getList();
		if (CollectionUtils.isNotEmpty(list)) {
			for (CtocOrderEntity entity : list) {
				MemberEntity member = memberService.selectById(entity.getMemberId());
				entity.setHeadImg(member.getHeadImg());
				entity.setNickname(StringUtils.isNotBlank(member.getNickname()) ? member.getNickname() : member.getRealname().substring(0, 1) + "**");
				Integer dealCount = ctocOrderService.selectCount(new EntityWrapper<CtocOrderEntity>().eq("status", ProjectConstant.CTOC_ORDER_STATUS_FINISH).eq("member_id",
						entity.getMemberId()));
				entity.setDealCount(dealCount);
				entity.setMobile(null);
			}
		}
		return R.ok().put("page", page);
	}

	@Login
	@PostMapping("detail")
	@ApiOperation("挂单详情")
	public R detail(@RequestParam("id") Long id) {
		CtocOrderEntity ctocOrder = ctocOrderService.selectById(id);
		Assert.notNull(ctocOrder, "订单不存在");
		MemberEntity member = memberService.selectById(ctocOrder.getMemberId());
		MemberOtherForm memberOther = new MemberOtherForm();
		try {
			BeanUtils.copyProperties(memberOther, member);
			if (StringUtils.isNotBlank(member.getRealname())) {
				memberOther.setRealname(member.getRealname().substring(0, 1) + "**");
			}
			memberOther.setMobile(memberOther.getMobile().substring(0, 3) + "********");

		} catch (Exception e) {
			e.printStackTrace();
		}
		return R.ok().put("ctocOrder", ctocOrder).put("member", memberOther);
	}

	@Login
	@PostMapping("mylist")
	@ApiOperation("我的挂单列表")
	public R mylist(@ApiIgnore @RequestParam Map<String, Object> params) {
		params.put("memberId", getUserId());
		return list(params);
	}

	@SuppressWarnings("unchecked")
	@Login
	@PostMapping("tradingList")
	@ApiOperation("进行中订单列表")
	public R needPayList(@ApiIgnore @RequestAttribute("userId") long userId, @ApiIgnore @RequestParam Map<String, Object> params) {
		params.put("status", 1);
		params.put("memberId", userId);
		PageUtils page = ctocTransactionService.queryPage(params);
		setInfo((List<CtocTransactionEntity>) page.getList(), userId);
		return R.ok().put("page", page);
	}

	@SuppressWarnings("unchecked")
	@Login
	@PostMapping("finishList")
	@ApiOperation("已完成订单列表")
	public R finishList(@ApiIgnore @RequestAttribute("userId") long userId, @ApiIgnore @RequestParam Map<String, Object> params) {
		params.put("status", 2);
		params.put("memberId", userId);
		PageUtils page = ctocTransactionService.queryPage(params);
		setInfo((List<CtocTransactionEntity>) page.getList(), userId);
		return R.ok().put("page", page);
	}

	@SuppressWarnings("unchecked")
	@Login
	@PostMapping("cancelList")
	@ApiOperation("取消订单列表")
	public R cancelList(@ApiIgnore @RequestAttribute("userId") long userId, @ApiIgnore @RequestParam Map<String, Object> params) {
		params.put("status", 3);
		params.put("memberId", userId);
		PageUtils page = ctocTransactionService.queryPage(params);
		setInfo((List<CtocTransactionEntity>) page.getList(), userId);
		return R.ok().put("page", page);
	}

	private void setInfo(List<CtocTransactionEntity> list, long userId) {
		if (CollectionUtils.isNotEmpty(list)) {
			for (CtocTransactionEntity entity : list) {
				MemberEntity member = null;
				if (userId == entity.getBuyerMemberId()) {
					member = memberService.selectById(entity.getSellerMemberId());
					// 付款时间倒计时
					if (entity.getStatus() == ProjectConstant.CTOC_TRANS_STATUS_NEEDPAY) {
						Date paymentTimeout = DateUtils.addDateMinutes(entity.getCreateTime(), sysConfigService.getValueI(ConfigConstant.BUYER_PAYMENT_TIMEOUT));
						entity.setCountDown(paymentTimeout.getTime() - System.currentTimeMillis());
					}
				} else {
					member = memberService.selectById(entity.getBuyerMemberId());
					// 确认时间倒计时
					if (entity.getStatus() == ProjectConstant.CTOC_TRANS_STATUS_PAID) {
						Date finishTimeout = DateUtils.addDateHours(entity.getPaymentTime(), sysConfigService.getValueI(ConfigConstant.SELLER_CONFIRM_TIMEOUT));
						entity.setCountDown(finishTimeout.getTime() - System.currentTimeMillis());
					}
				}
				entity.setHeadImg(member.getHeadImg());
			}
		}
	}

	@Login
	@PostMapping("transDetail")
	@ApiOperation("订单详情")
	public R transDetail(@RequestParam("id") Long id) {
		CtocTransactionEntity ctocTransaction = ctocTransactionService.selectById(id);
		return R.ok().put("ctocTransaction", ctocTransaction);
	}

	@Login
	@PostMapping("buy")
	@ApiOperation("发布买单")
	public R buy(@ApiIgnore @LoginUser MemberEntity member, @RequestBody BuyForm form) {
		checkInfo(member, null);
		// 表单校验
		ValidatorUtils.validateEntity(form);
		Assert.isTrue(form.getCoinQuantity() > 0, "数量无效");
		int minQty = sysConfigService.getValueI(ConfigConstant.COIN_MIN_QTY);
		Assert.isTrue(form.getCoinQuantity() >= minQty, "最低起买数量为" + minQty + "个AIC");
		Assert.isTrue(form.getCoinPrice() <= sysConfigService.getValueD(ConfigConstant.ORDER_MAX_PRICE), "您的买入价格已偏离市场最大限制");

		CtocOrderEntity ctocOrder = new CtocOrderEntity();
		ctocOrder.setMemberId(member.getId());
		ctocOrder.setMobile(member.getMobile());
		ctocOrder.setOrderNo("C" + DateUtils.format(new Date(), "yyyyMMddHH") + RandomStringUtils.randomNumeric(5));
		ctocOrder.setCoinPrice(form.getCoinPrice());
		ctocOrder.setCoinQuantity(form.getCoinQuantity());
		ctocOrder.setCoinTotalPrice(DecimalUtils.mul(form.getCoinPrice(), form.getCoinQuantity()));
		ctocOrder.setStatus(ProjectConstant.CTOC_ORDER_STATUS_SUBMIT);
		ctocOrder.setCreateTime(new Date());
		ctocOrderService.insert(ctocOrder);
		return R.ok();
	}

	@Login
	@PostMapping("cancelBuy")
	@ApiOperation("撤销挂单")
	public R cancelBuy(@ApiIgnore @RequestAttribute("userId") long userId, @RequestParam("id") Long id) {
		Assert.notNull(id, "订单ID不能为空");
		CtocOrderEntity ctocOrder = ctocOrderService.selectById(id);
		Assert.notNull(ctocOrder, "订单不存在");
		Assert.isTrue(userId == ctocOrder.getMemberId(), "此订单不属于您");
		Assert.isTrue(ctocOrder.getStatus() == ProjectConstant.CTOC_ORDER_STATUS_SUBMIT, "订单正在交易或已完成无法取消");

		ctocOrder.setStatus(ProjectConstant.CTOC_ORDER_STATUS_CANCEL);
		ctocOrder.setUpdateTime(new Date());
		ctocOrderService.updateById(ctocOrder);

		return R.ok();
	}

	@Login
	@PostMapping("sell")
	@ApiOperation("卖出虚拟币")
	public R sell(@ApiIgnore @LoginUser MemberEntity member, @RequestBody SellForm form) {
		checkInfo(member, Integer.MAX_VALUE);
		// 表单校验
		ValidatorUtils.validateEntity(form);
		Assert.isTrue(member.getPayword().equals(DigestUtils.sha256Hex(form.getPayword() + member.getSalt())), "支付密码错误");
		ctocTransactionService.sell(member, form.getId());
		return R.ok();
	}

	@Login
	@PostMapping("cancelTrans")
	@ApiOperation("取消交易")
	public R cancelTrans(@ApiIgnore @LoginUser MemberEntity member, @RequestParam("transId") Long transId) {
		Assert.notNull(transId, "交易ID不能为空");
		ctocTransactionService.cancelTrans(member, transId);
		return R.ok();
	}

	@Login
	@PostMapping("buyerPay")
	@ApiOperation("买家确认付款")
	public R buyerPay(@RequestParam("transId") Long transId) {
		Assert.notNull(transId, "交易ID不能为空");
		CtocTransactionEntity ctocTransaction = ctocTransactionService.selectById(transId);
		Assert.notNull(ctocTransaction, "交易不存在");
		Assert.isTrue(ctocTransaction.getBuyerMemberId().equals(getUserId()), "此订单您无法确认付款");
		Assert.isTrue(ctocTransaction.getStatus() == ProjectConstant.CTOC_TRANS_STATUS_NEEDPAY, "当前交易状态不可确认付款");
		if (sysConfigService.getValueI(ConfigConstant.MUST_TRANS_PROOF) == ProjectConstant.COMMON_YES) {
			Assert.hasText(ctocTransaction.getTransProofImg(), "请上传付款凭证");
		}

		// 更新交易状态
		Date now = new Date();
		ctocTransaction.setUpdateTime(now);
		ctocTransaction.setPaymentTime(now);
		ctocTransaction.setStatus(ProjectConstant.CTOC_TRANS_STATUS_PAID);
		ctocTransactionService.updateById(ctocTransaction);

		// 短信通知卖家
		SMSManages sms = new SMSManages(sysConfigService.getValue(ConfigConstant.SMS_USER), sysConfigService.getValue(ConfigConstant.SMS_PWD),
				sysConfigService.getValue(ConfigConstant.SMS_VERY_CODE));
		String retCode = sms.sendSMS(ctocTransaction.getSellerMobile(), "JSM42425-0002", "@1@=" + ctocTransaction.getOrderNo());
		System.out.println("sell retCode：" + retCode);
		return R.ok();
	}

	@Login
	@PostMapping("sellerConfirm")
	@ApiOperation("卖家确认收款")
	public R sellerConfirm(@ApiIgnore @LoginUser MemberEntity member, @RequestParam("transId") Long transId) {
		Assert.notNull(transId, "交易ID不能为空");
		ctocTransactionService.sellerConfirm(member, transId);
		return R.ok();
	}

	@Login
	@PostMapping("/upload/proof")
	@ApiOperation("上传付款凭证")
	public R uploadProof(@ApiIgnore @LoginUser MemberEntity member, @RequestParam("file") MultipartFile file, @RequestHeader("transId") Long transId) {
		Assert.notNull(transId, "交易ID不能为空");
		CtocTransactionEntity ctocTransaction = ctocTransactionService.selectOne(new EntityWrapper<CtocTransactionEntity>().setSqlSelect("id", "status", "trans_proof_img",
				"buyer_member_id").eq("id", transId));
		Assert.notNull(ctocTransaction, "交易不存在");
		Assert.isTrue(member.getId().equals(ctocTransaction.getBuyerMemberId()), "此交易不属于您");
		Assert.isTrue(ctocTransaction.getStatus() == ProjectConstant.CTOC_TRANS_STATUS_NEEDPAY, "此交易不允许上传凭证");

		if (file == null || file.isEmpty()) {
			throw new RRException("上传文件不能为空");
		}
		// 上传文件
		String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
		Assert.isImage(suffix, "请上传图片文件");
		try {
			// 生成文件名
			String fileName = UUID.randomUUID().toString().replaceAll("-", "") + suffix;
			// 文件路径
			String path = "proof/" + DateUtils.format(new Date(), "yyyyMMdd") + "/";
			// 压缩图片
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			Thumbnails.of(file.getInputStream()).scale(1f).outputQuality(0.5f).toOutputStream(bos);
			String url = OSSFactory.build().upload(bos.toByteArray(), path + fileName);

			Date now = new Date();

			if (StringUtils.isNotBlank(ctocTransaction.getTransProofImg())) {
				SysOssEntity oss = sysOssService.selectOne(new EntityWrapper<SysOssEntity>().setSqlSelect("id").eq("url", ctocTransaction.getTransProofImg()));
				if (oss != null) {
					oss.setFlag(ProjectConstant.COMMON_YES);
					sysOssService.updateById(oss);
				}
			}

			// 保存文件信息
			SysOssEntity ossEntity = new SysOssEntity();
			ossEntity.setUrl(url);
			ossEntity.setCreateDate(now);
			sysOssService.insert(ossEntity);

			// 保存交易凭证
			ctocTransaction.setTransProofImg(url);
			ctocTransaction.setUpdateTime(now);
			ctocTransactionService.updateById(ctocTransaction);
		} catch (Exception e) {
			logger.error("上传文件失败", e);
			throw new RRException("上传文件失败");
		}

		return R.ok();
	}

	/**
	 * 检查账号信息
	 * 
	 * @param member
	 * @param type
	 */
	private void checkInfo(MemberEntity member, Integer type) {
		Assert.isTrue(member.getStatus() == ProjectConstant.COMMON_STATUS_ENABLE, "账号被禁止交易");
		Assert.isTrue(member.getAuthStatus() == ProjectConstant.AUTH_STATUS_PASSED, "未实名认证");

		Date now = new Date();
		String startOfDay = DateUtils.format(now);
		// 判断市场是否收盘
		String[] openCloseTime = sysConfigService.getValue(ConfigConstant.OPEN_CLOSE_TIME).split("-");
		Date openTime = DateUtils.stringToDate(startOfDay + " " + openCloseTime[0], DateUtils.DATE_TIME_PATTERN);
		Date closeTime = DateUtils.stringToDate(startOfDay + " " + openCloseTime[1], DateUtils.DATE_TIME_PATTERN);
		int compare = closeTime.compareTo(openTime);
		if (compare == 1) {
			// 未跨天
			if (openTime.after(now) || closeTime.before(now)) {
				throw new RRException("市场已收市");
			}
		} else if (compare == -1) {
			// 跨天
			if (now.before(openTime) && now.before(closeTime)) {
			} else if (now.after(openTime) && now.after(closeTime)) {
			} else {
				throw new RRException("市场已收市");
			}
		}

		if (StringUtils.isBlank(member.getAlipay()) && StringUtils.isBlank(member.getWechat()) && StringUtils.isBlank(member.getBankCardNumber())) {
			throw new RRException("未设置收款信息");
		}

		if (type != null) {
			Assert.hasText(member.getPayword(), "未设置支付密码");
		}

		CtocTransCountEntity entity = ctocTransCountService.selectOne(new EntityWrapper<CtocTransCountEntity>().eq("member_id", member.getId()).ge("create_time", startOfDay));
		if (entity != null) {
			if (entity.getOrderCancel() != null && entity.getOrderCancel() >= sysConfigService.getValueI(ConfigConstant.ORDER_CANCEL_TIMES)) {
				throw new RRException("当日订单取消次数过多，被禁止交易");
			}
		}
	}
}
